package com.google.code.gronono.gps.ui.panels.pages.tree;

import java.io.File;
import java.util.Arrays;
import java.util.Map;
import java.util.TreeMap;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreeModel;

import com.google.code.gronono.gps.model.SortedFile;
import com.google.code.gronono.gps.ui.controller.GPSController;

/**
 * Factory permettant la création des modèles des arbres du résultat du traitement.
 * @author Arnaud BRUNET
 */
public class TreeModelFactory {
	/** Le contrôleur. */
	private final GPSController controller;

	/**
	 * Constructeur.
	 * @param controller Le contrôleur.
	 */
	public TreeModelFactory(final GPSController controller) {
		this.controller = controller;
	}

	/**
	 * Créer le modèle de l'arbre affichant les fichiers sources.
	 * @return Le modèle.
	 */
	public TreeModel createSrcModel() {
		// Récupération de la liste de résultats du traitement
		final SortedFile[] sortedFiles = controller.getSortedFiles();
		// Tri de cette liste
		Arrays.sort(sortedFiles);

		DefaultMutableTreeNode rootNode = null;

		// Génère la map 'en vrac'
		final Map<SortedFile, DefaultMutableTreeNode> map = new TreeMap<SortedFile, DefaultMutableTreeNode>();
		for (final SortedFile f : sortedFiles) {
			// On n'affiche le fichier source que s'il existe physiquement
			// (permet de visualiser plus facilement ce qui peut rester après un tri en mode déplacement)
			if (f.getSrcFile().exists()) {
				map.put(f, new DefaultMutableTreeNode(f));
			}
		}

		// Etablit les liens père/fils entre les noeuds
		for (final SortedFile f : map.keySet()) {
			final File parent = f.getSrcFile().getParentFile();
			if (parent != null) {
				final DefaultMutableTreeNode parentNode = map.get(new SortedFile(parent));
				if (parentNode == null) {
					rootNode = map.get(f);
				} else {
					final MutableTreeNode fileNode = map.get(f);
					parentNode.add(fileNode);
				}
			} else {
				rootNode = map.get(f);
			}
		}

		return new DefaultTreeModel(rootNode);
	}

	/**
	 * Créer le modèle de l'arbre affichant les fichiers de destination.
	 * @return Le modèle.
	 */
	public TreeModel createDstModel() {
		// Récupération de la liste de résultats du traitement
		final SortedFile[] sortedFiles = controller.getSortedFiles();
		// Pas de tri car on parcourt dans l'ordre de la source

		DefaultMutableTreeNode rootNode = null;

		// Pour la cible le dossier de base est le dossier spécifié
		final File dstDir = controller.getConfiguration().getDstDir();
		final SortedFile dstSortedFile = new SortedFile(dstDir, dstDir);

		// Génère la map 'en vrac'
		final Map<SortedFile, DefaultMutableTreeNode> map = new TreeMap<SortedFile, DefaultMutableTreeNode>();
		map.put(dstSortedFile, new DefaultMutableTreeNode(dstSortedFile));
		for (final SortedFile f : sortedFiles) {
			// On n'affiche que les fichiers pour lesquels une cible à bien été déterminée
			if (f.getDstFile() != null) {
				map.put(f, new DefaultMutableTreeNode(f));
				File parent = f.getDstFile().getParentFile();
				SortedFile parentSorted = new SortedFile(parent, parent);
				// On génère les noeuds (répertoires) intermédiaires manquants
				while (!parent.equals(dstDir) && !map.containsKey(parentSorted)) {
					map.put(parentSorted, new DefaultMutableTreeNode(parentSorted));
					parent = parent.getParentFile();
					parentSorted = new SortedFile(parent, parent);
				}
			}
		}

		// Etablit les liens père/fils entre les noeuds
		for (final SortedFile f : map.keySet()) {
			final SortedFile parentSortedFile = new SortedFile(f.getDstFile().getParentFile(), f.getDstFile().getParentFile());
			final DefaultMutableTreeNode parentNode = map.get(parentSortedFile);
			if (parentNode == null) {
				rootNode = map.get(f);
			} else {
				parentNode.add(map.get(f));
			}
		}

		return new DefaultTreeModel(rootNode);
	}
}
